﻿using System;
using System.Collections.Generic;
using System.Resources;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Deferred.Editor.Content;
using Deferred.Editor.Gui.Scene;
using Deferred.Library;
using Deferred.Library.Configuration;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using WeifenLuo.WinFormsUI.Docking;
using FormsRectangle = System.Drawing.Rectangle;

namespace Deferred.Editor.Gui
{
    public partial class DeferredEditor : Form
    {
        private static readonly DockAreas DockAll = DockAreas.DockBottom | DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.Float;

        private ContentBuilder builder = new ContentBuilder();
        private List<DeferredWindow> windows = new List<DeferredWindow>();
        private DeferredWindow renderWindow;
        private DeferredBase deferredBase;
        private ContentUpdater sceneUpdater;
        private ContentChooserWindow chooserWindow = new ContentChooserWindow();

        private Rectangle RenderBounds
        {
            get
            {
                FormsRectangle bounds;
                if (dockPanel.DockWindows[DockState.Document] != null)
                {
                    bounds = dockPanel.DockWindows[DockState.Document].Bounds;
                }
                else
                {
                    bounds = Bounds;
                }
                return new Rectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height);
            }
        }

        public DeferredEditor()
        {
            InitializeComponent();

            setupDeferredBase();
            setupServices();
            setupWindows();

            this.Shown += openContentToolStripMenuItem_Click;
        }

        private void setupDeferredBase()
        {
            GameServiceContainer services = new GameServiceContainer();
            IGraphicsDeviceService deviceService = new GraphicsDeviceService(Handle, RenderBounds.Width, RenderBounds.Height);
            ContentManager deferredContent = new ContentManager(services, builder.OutputDirectory);
            ResourceContentManager internalManager = new ResourceContentManager(services, new ResourceManager(typeof(LibraryContent)));

            deferredBase = new DeferredBase(services, new DualContentManager(internalManager, deferredContent), deviceService);

            sceneUpdater = new ContentUpdater(this, deferredContent, builder, chooserWindow);
            sceneUpdater.CurrentSceneChanged += new EventHandler(delegate(object s, EventArgs e) { sceneUpdated(); });
            sceneUpdater.OpenContentCompleted += new EventHandler(delegate(object s, EventArgs e) { OpenContentCompleted(); });
        }

        private void setupWindows()
        {
            IOptions options = (IOptions)deferredBase.Services.GetService(typeof(IOptions));
            ICommandLineEngine commandLine = (ICommandLineEngine)deferredBase.Services.GetService(typeof(ICommandLineEngine));

            renderWindow = addDockedWindow(new RenderControl(deferredBase, sceneUpdater), "Render", DockAreas.Document, DockState.Document);
            ((GraphicsDeviceService)deferredBase.DeviceService).ResetDevice(renderWindow.Content.Handle, RenderBounds.Width, RenderBounds.Height);
            windows.Add(renderWindow);

            windows.Add(addDockedWindow(new OptionsPanel(options), "Options", DockAll, DockState.DockLeftAutoHide));
            windows.Add(addDockedWindow(new CommandLinePanel(commandLine), "Command", DockAll, DockState.DockBottom));
            windows.Add(addDockedWindow(new ScenePanel(deferredBase, sceneUpdater, chooserWindow), "Scene", DockAll, DockState.DockRightAutoHide));
        }

        private void setupServices()
        {
            IFocusHelper focusHelper = new FocusHelper();
            deferredBase.Services.AddService(typeof(IFocusHelper), focusHelper);

            ICommandLineEngine commandLine = new CommandLineEngine();
            deferredBase.Services.AddService(typeof(ICommandLineEngine), commandLine);

            IOptions options = new Options(deferredBase.Services);
            deferredBase.Services.AddService(typeof(IOptions), options);

            deferredBase.Services.AddService(typeof(IGraphicsDeviceService), deferredBase.DeviceService);

            commandLine.AddCommand("exit", "Exits the program",
                delegate(string[] arguments)
                {
                    this.Close();
                    return null;
                }
            );

            dockPanel.ActiveContentChanged += new EventHandler(delegate(object sender, EventArgs e) { focusHelper.GameHasFocus = dockPanel.ActiveContent == renderWindow; });
        }

        private void sceneUpdated()
        {
            bool sceneIsNull = sceneUpdater.CurrentScene == null;

            foreach (DeferredWindow window in windows)
            {
                if (sceneIsNull)
                    window.Hide();
                else
                    window.Show();
            }

            saveSceneToolStripMenuItem.Enabled = !sceneIsNull;
            saveSceneAsToolStripMenuItem.Enabled = !sceneIsNull;
            closeSceneToolStripMenuItem.Enabled = !sceneIsNull;
        }

        private void OpenContentCompleted()
        {
            openContentToolStripMenuItem.Enabled = true;
            toolStripProgressBar.Visible = false;
            toolStripStatusLabel.Visible = false;
            newSceneToolStripMenuItem.Enabled = sceneUpdater.HasContent;
            openSceneToolStripMenuItem.Enabled = sceneUpdater.HasContent;
            WindowFlasher.Flash(this);
        }

        private DeferredWindow addDockedWindow(Control dockedControl, string windowName, DockAreas validAreas, DockState dockState)
        {
            DeferredWindow window = new DeferredWindow(dockedControl, windowName);
            window.DockAreas = validAreas;
            window.Size = dockPanel.DockWindows[dockState].Size;
            window.Show(dockPanel, dockState);
            window.Hide();

            return window;
        }

        private void openContentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (sceneUpdater.openContent())
            {
                openContentToolStripMenuItem.Enabled = false;
                toolStripProgressBar.Visible = true;
                toolStripStatusLabel.Visible = true;
                toolStripStatusLabel.Text = "Building Content";
            }
        }

        private void newSceneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            sceneUpdater.createNewScene();
        }

        private void openSceneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            sceneUpdater.openScene();
        }

        private void closeSceneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            sceneUpdater.closeScene();
        }

        private void saveSceneToolStripMenuItem_Click(object sender, EventArgs e)
        {
            sceneUpdater.SaveScene();
        }

        private void saveSceneAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            sceneUpdater.SaveSceneAs();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void DeferredEditor_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = !sceneUpdater.PromptAndSaveScene();
        }
    }
}
